/**
 * 工具类
 * @author xxmi.org
 * @date 2021年5月10日
 */
import np from "number-precision";
/**
 * 数据类型
 */
export enum DataTypes {
	Object = "object",
	Array = "array",
	String = "string",
	Number = "number",
	Boolean = "boolean",
	Undefined = "undefined",
	Null = "null",
	Math = "math",
	Function = "function",
}

/**
 * 获取数据类型
 * @param args 参数
 */
export function getDataType(args : any) : string {
	const match = Object.prototype.toString.call(args).match(/\[object (.*?)\]/);
	if (match === null) {
		throw new Error("未知类型");
	}
	return match[1].toLowerCase();
}

/**
 * 是否为对象类型
 * @param args
 */
export function isObjectType(args : any) : boolean {
	return getDataType(args) === DataTypes.Object;
}

/**
 * 是否为数组类型
 * @param args
 */
export function isArrayType(args : any) : boolean {
	return getDataType(args) === DataTypes.Array;
}

/**
 * 是否为字符串类型
 * @param args
 */
export function isStringType(args : any) : boolean {
	return getDataType(args) === DataTypes.String;
}

/**
 * 是否为数字类型
 * @param args
 */
export function isNumberType(args : any) : boolean {
	return getDataType(args) === DataTypes.Number;
}

/**
 * 是否为布尔值类型
 * @param args
 */
export function isBooleanType(args : any) : boolean {
	return getDataType(args) === DataTypes.Boolean;
}

/**
 * 是否为未定义类型
 * @param args
 */
export function isUndefinedType(args : any) : boolean {
	return getDataType(args) === DataTypes.Undefined;
}

/**
 * 是否为 null 类型
 * @param args
 */
export function isNullType(args : any) : boolean {
	return getDataType(args) === DataTypes.Null;
}

/**
 * 是否为 Math 类型
 * @param args
 */
export function isMathType(args : any) : boolean {
	return getDataType(args) === DataTypes.Math;
}

/**
 * 是否为函数类型
 * @param args
 */
export function isFunctionType(args : any) : boolean {
	return getDataType(args) === DataTypes.Function;
}

/**
 * 判断是否为空
 * 符合条件：
 * undefined
 * null
 * ''
 * val.length <= 0
 * @param val 判断的值
 * @returns {boolean}
 */
export function isEmpty(val : any) : boolean {
	return (
		typeof val === "undefined" ||
		val === null ||
		val === "" ||
		(Array.isArray(val) && val.length <= 0)
	);
}

/**
 * 判断是一个整数
 * @param {string} val 判断的值
 * @returns {boolean}
 */
export function isInteger(val : string) : boolean {
	return /^\d+$/.test(String(val));
}

/**
 * 整数或者小数
 * @param {string|number} val 判断的值
 * @returns {boolean}
 */
export function isIntegerOrDecimal(val : string) : boolean {
	return /^(-[1-9]\d*|[\d]|[1-9]\d*|-?([1-9]\d*|\d)\.\d+)$/.test(String(val));
}

/**
 * 目标对象
 */
export interface TargetObject {
	[key : string] : any;
}

/**
 * 交换属性
 */
export interface ExchangeProperty {
	[key : string] : string;
}

/**
 * 扩展属性
 */
export interface ExtendProperty {
	[key : string] : any;
}

/**
 * 扩展属性
 *
 * 示例：
 * const targetObj = {id: 1001, url: 'xxmi.cn'};
 * const property = {uri:'url'}
 * const extend = {async: true};
 * const ep = _extendProperty(targetObj, property, extend);
 *
 * 原值：{ id: 1001, url: 'xxmi.cn' }
 * 结果：{ id: 1001, url: 'xxmi.cn', uri: 'xxmi.cn', async: true }
 * @param targetObject 目标对象（目标对象会被修改）
 * @param exchangeProperty 新增属性 {new:old} 把old属性的值写入new中
 * @return {*}
 */
export function _extendProperty(
	targetObject : TargetObject,
	exchangeProperty : ExchangeProperty = {},
	extendProperty : ExtendProperty = {}
) {
	for (const newKey in exchangeProperty) {
		const oldKey = exchangeProperty[newKey];
		targetObject[newKey] = targetObject[oldKey];
	}
	return Object.assign(targetObject, exchangeProperty, extendProperty);
}

/**
 * 扩展属性
 * @param {Object|Array<Object>>}targetObject 目标对象
 * @param property 新增属性 {new:old} 把old属性的值写入new中
 * @param extend 扩展属性 {async: true}
 * @return {*}
 */
export function extendProperty(
	targetObject : TargetObject | Array<TargetObject>,
	property = {},
	extend = {}
) {
	if (Array.isArray(targetObject)) {
		for (const item of targetObject) {
			_extendProperty(item, property, extend);
		}
	} else {
		targetObject = _extendProperty(targetObject, property, extend);
	}
	return targetObject;
}

/**
 * 删除指定属性
 * @param {Object} targetObject - 目标对象
 * @param {string|Array<string>>} deleteProperty - 删除的属性（key）
 * @returns {Object}
 */
export function deleteProperty(
	targetObject : TargetObject,
	deleteProperty : string | Array<string>
) {
	const deleteProperty_ = Array.isArray(deleteProperty)
		? deleteProperty
		: [deleteProperty];
	for (const deleteKey of deleteProperty_) {
		if (targetObject.hasOwnProperty(deleteKey)) {
			delete targetObject[deleteKey];
		}
	}
	return targetObject;
}

/**
 * 删除空属性
 * @param {Object} targetObject - 对象
 * @param {string|Array<string>>} deleteProperty - 删除的属性（key）
 * @returns {Object}
 */
export function deleteEmptyProperty(
	targetObject : TargetObject,
	delProperty : string | Array<string> = []
) {
	for (const key in targetObject) {
		if (isEmpty(targetObject[key])) {
			delete targetObject[key];
		}
	}
	return deleteProperty(targetObject, delProperty);
}

export interface Node {
	[key : string] : any;
}

/**
 * 解析 Tree
 * @param nodes 数据节点数组
 * @param settings 配置
 * @param property {new:old} 把 old 写入 new 中（新增属性）
 * @params extend 扩展属性 {async: true}
 * @returns []
 */
export function parseTree(
	nodes : Array<Node>,
	settings = {
		key: "id",
		parentKey: "pid",
		childKey: "children",
	},
	property = {},
	extend = {}
) {
	const { key, parentKey, childKey } = settings;
	if (!Array.isArray(nodes)) {
		return [nodes];
	}

	const nodes_ = [];
	const tmpMap : any = {};
	for (let i = 0, l = nodes.length; i < l; i++) {
		nodes[i] = _extendProperty(nodes[i], property, extend);
		tmpMap[nodes[i][key]] = nodes[i];
	}
	for (let i = 0, l = nodes.length; i < l; i++) {
		if (tmpMap[nodes[i][parentKey]] && nodes[i][key] !== nodes[i][parentKey]) {
			if (!tmpMap[nodes[i][parentKey]][childKey]) {
				tmpMap[nodes[i][parentKey]][childKey] = [];
			}
			tmpMap[nodes[i][parentKey]][childKey].push(nodes[i]);
		} else {
			nodes_.push(nodes[i]);
		}
	}
	return nodes_;
}

/**
 * 处理微信通过 ？号传递的参数解码
 * @param data
 */
export function decode<T = Record<string, any>>(data : T) : T {
	for (const key in data) {
		(data as any)[key] = decodeURI((data as any)[key]);
	}
	return data;
}

/**
 * 验证手机号码
 * @param phone 手机号码
 */
export function isPhone(phone : string) : boolean {
	return /^1(3|4|5|6|7|8|9)\d{9}$/.test(phone);
}

export function isVehicleNumber() { }

/**
 * 延期执行
 * @param time 延期时间-毫秒
 */
export function delayExec(time = 0) : Promise<void> {
	return new Promise((resolve) => {
		setTimeout(() => {
			resolve();
		}, time);
	});
}


/**
 * 元转分
 * @param num 
 * @returns 分
 */
export function dollarToPenny(num : number) : number {
	if (!isIntegerOrDecimal(String(num))) return 0;
	return np.times(num, 100);
}

/**
 * 分转元
 * @param num 
 * @returns 元
 */
export function pennyToDollar(num : number) : number {
	if (!isIntegerOrDecimal(String(num))) return 0;
	return np.divide(num, 100);
}

/**
 * 验证是否为邮箱
 * @param {string} email 
 * @return 
 */ 
export function isValidateEmail(email : string) {
	const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
	return emailRegex.test(email);
}